package ldh.im.fxbase.richtext;

import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Path;
import javafx.scene.shape.PathElement;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.HitInfo;
import javafx.scene.text.Text;

import java.util.ArrayList;
import java.util.List;

public class ImTextPane extends AnchorPane {

    private TextFlowExt textFlowExt;
    private Path selectPath = new Path();

    private Rectangle clickPoint = new Rectangle();
    private int start=0, end =0;

    private List<Object> items = new ArrayList();
    private String content;

    public static String COPY_HEADER = "~!*+";

    public ImTextPane() {
        this.getStyleClass().add("im-text-pane");
        textFlowExt = new TextFlowExt();

        selectPath.setMouseTransparent(true);
        this.setMouseTransparent(false);

        Group group = new Group();
        group.getChildren().addAll(textFlowExt, selectPath);
        this.getChildren().addAll(group);
//        StackPane.setAlignment(group, Pos.TOP_LEFT);
//        StackPane.setAlignment(selectPath, Pos.TOP_LEFT);
        AnchorPane.setTopAnchor(group, 2d);
        AnchorPane.setLeftAnchor(group, 2d);
        AnchorPane.setBottomAnchor(group, 2d);
        AnchorPane.setRightAnchor(group, 2d);

        bindEvent();
    }

    public void setImContent(String content) {
        this.content = content;
        String[] strs = content.split(TextItem.SPLIT_STRING2);
        for(String s : strs) {
            if (s.equals("")) continue;
            TextItem textItem = TextItem.parse(s);
            if (textItem == null) {
                items.add(s);
                textFlowExt.getChildren().add(new Text(s));
            } else {
                insertTextItem(textItem);
                items.add(textItem);
            }
        }
    }

    public void setContent(String content) {
        this.content = content;
        items.add(content);
        textFlowExt.getChildren().add(new Text(content));
    }

    public void insertTextItem(TextItem textItem) {
        textFlowExt.getChildren().add(textItem.createNode());
    }

    private void bindEvent() {
        textFlowExt.setOnMousePressed(e->{
            clickPoint.setX(e.getX());
            clickPoint.setY(e.getY());

            ImTextPane.this.requestFocus();

            selectPath.getElements().clear();
        });

        textFlowExt.setOnMouseDragged(e->{
            select(e);
        });

        this.widthProperty().addListener(e->{
            textFlowExt.setMaxWidth(ImTextPane.this.getWidth()-4);
            textFlowExt.setPrefWidth(ImTextPane.this.getWidth()-4);
            textFlowExt.setMinWidth(ImTextPane.this.getWidth()-4);
        });

        textFlowExt.setOnKeyPressed(e->{
            if(e.isControlDown() && e.getCode() == KeyCode.C) {
                copy();
            }
        });
        this.setOnKeyPressed(e->{
            if(e.isControlDown() && e.getCode() == KeyCode.C) {
                copy();
            }
        });

        this.setOnMouseClicked(e->{
            if(e.getClickCount() == 2) {
                selectAll();
            }
        });

        textFlowExt.focusedProperty().addListener(e->{
            if (!textFlowExt.focusedProperty().get() && !ImTextPane.this.focusedProperty().get()) {
                clearSelect();
            }
        });
    }

    private void selectAll() {
        start = 0;
        end = content.length();
        if (start == end) return;
        selectText(start, end);
    }

    private void select(MouseEvent e) {
        HitInfo characterHit = textFlowExt.hitTest(new Point2D(e.getX(), e.getY()));

        HitInfo startHit = textFlowExt.hitTest(new Point2D(clickPoint.getX(), clickPoint.getY()));
        int start1 = startHit.getCharIndex();

        int end1 = characterHit.getCharIndex();

        if (start1 > end1) {
            int t = end1;
            end1 = start1+1;
            start1 = t;
        } else {
            end1++;
        }
        start = start1;
        end = end1;

        selectText(start, end);
    }

    private void selectText(int start, int end) {
        PathElement[] pes = textFlowExt.getRangeShape(start, end);

        selectPath.setStroke(null);
        selectPath.setFill(Color.web("#0000CC"));
        selectPath.setOpacity(0.3);
        selectPath.getElements().clear();
        selectPath.getElements().addAll(pes);

        textFlowExt.requestFocus();
    }

    public TextFlowExt getTextFlowExt() {
        return textFlowExt;
    }

    private void copy() {
        StringBuilder sb = new StringBuilder();
        if (!(start >= 0 && end >0)) return;
        int length = 0;
        boolean isStart = false;
        for(Object s : items) {
            if (s instanceof String) {
                String str = (String) s;
                int strLength = str.length();
                if (strLength > start - length && start - length >= 0) {
                    isStart = true;
                    if (strLength >= end - length) {
                        sb.append(str.substring(start-length, end-length));
                        break;
                    } else {
                        sb.append(str.substring(start-length));
                    }
                } else if (strLength >= end-length && isStart) {
                    sb.append(str.substring(0, end-length));
                    break;
                } else if (strLength < end - length && isStart) {
                    sb.append(str);
                }
                length += strLength;
            } else {
                TextItem textItem = (TextItem) s;
                int strLength = 1;
                if (strLength > start - length && start - length >= 0) {
                    isStart = true;
                    if (strLength <= end - length) {
                        sb.append(textItem.getImData());
                    }
                } else if (strLength <= end - length  && isStart) {
                    sb.append(textItem.getImData());
                } else if (isStart)
                    break;
                length += strLength;
            }
        }
        copyData(sb.toString());
    }

    private void clearSelect() {
        selectPath.getElements().clear();
        start = 0;
        end = 0;
    }

    private void copyData(String str) {
        Clipboard clipboard = Clipboard.getSystemClipboard();
        ClipboardContent content = new ClipboardContent();
        content.putString(COPY_HEADER + str);
        clipboard.setContent(content);
    }

}
